﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;

namespace Micua.Utility
{
    /// <summary> 
    /// 验证码类
    /// </summary> 
    public class VerifyCode
    {
        #region 字段
        private static readonly string[] FontItems =
        { 
            "Arial", 
            "Helvetica", 
            "Geneva", 
            "sans-serif", 
            "Verdana" 
        };
        private static readonly Brush[] BrushItems =
        { 
            Brushes.OliveDrab, 
            Brushes.ForestGreen, 
            Brushes.DarkCyan, 
            Brushes.LightSlateGray, 
            Brushes.RoyalBlue, 
            Brushes.SlateBlue, 
            Brushes.DarkViolet, 
            Brushes.MediumVioletRed, 
            Brushes.IndianRed, 
            Brushes.Firebrick, 
            Brushes.Chocolate, 
            Brushes.Peru, 
            Brushes.Goldenrod 
        };
        private static readonly string[] BrushName =
        { 
            "OliveDrab",
            "ForestGreen", 
            "DarkCyan", 
            "LightSlateGray", 
            "RoyalBlue", 
            "SlateBlue",
            "DarkViolet", 
            "MediumVioletRed", 
            "IndianRed", 
            "Firebrick", 
            "Chocolate", 
            "Peru", 
            "Goldenrod" 
        };
        private readonly Color _background;
        private readonly Pen _borderColor;
        private readonly Font _font;
        private readonly int _width;
        private readonly int _height;
        private readonly Random _random;
        private int _brushNameIndex;
        #endregion

        /// <summary>
        /// 验证码
        /// </summary>
        public string Code { get; private set; }

        #region 构造函数

        /// <summary>
        /// 构造一个验证码对象
        /// </summary>
        /// <param name="length">验证码长度</param>
        /// <param name="width">图片宽度</param>
        /// <param name="height">图片高度</param>
        /// <param name="fontSize">字体大小</param>
        /// <param name="background">背景色</param>
        /// <param name="border">边框颜色</param>
        public VerifyCode(byte length = 4, short width = 50, short height = 20, float fontSize = 12, Color background = default(Color), Pen border = default(Pen))
        {
            _random = new Random();
            _background = background;
            _borderColor = border ?? Pens.White;
            _font = GetFont(fontSize);
            _width = width;
            _height = height;
            Code = GetRandomCode(length);
        }
        #endregion

        #region 取得一个指定位数的随机码 _static string GetRandomCode(int length)
        /// <summary> 
        /// 取得一个指定位数的随机码 
        /// </summary> 
        /// <returns></returns> 
        private static string GetRandomCode(int length)
        {
            return Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, length);
        }
        #endregion

        #region 随机取一个字体 _Font GetFont()
        /// <summary> 
        /// 随机取一个字体 
        /// </summary> 
        /// <returns></returns> 
        private Font GetFont(float fontSize)
        {
            int fontIndex = _random.Next(0, FontItems.Length);
            FontStyle fontStyle = GetFontStyle(_random.Next(0, 2));
            return new Font(FontItems[fontIndex], fontSize, fontStyle);
        }
        #endregion

        #region 取一个字体的样式 _static FontStyle GetFontStyle(int index)
        /// <summary> 
        /// 取一个字体的样式 
        /// </summary> 
        /// <param name="index"></param> 
        /// <returns></returns> 
        private static FontStyle GetFontStyle(int index)
        {
            switch (index)
            {
                case 0:
                    return FontStyle.Bold;
                case 1:
                    return FontStyle.Italic;
                default:
                    return FontStyle.Regular;
            }
        }
        #endregion

        #region 随机取一个笔刷 _Brush GetBrush()
        /// <summary> 
        /// 随机取一个笔刷 
        /// </summary> 
        /// <returns></returns> 
        private Brush GetBrush()
        {
            int brushIndex = _random.Next(0, BrushItems.Length);
            _brushNameIndex = brushIndex;
            return BrushItems[brushIndex];
        }
        #endregion

        #region 画出位图 +Bitmap DrawBitmap()
        /// <summary> 
        /// 画出位图，注意对返回值使用过后的资源释放 
        /// </summary> 
        public byte[] DrawBitmap()
        {
            using (var image = new Bitmap(_width, _height))
            {
                using (var g = Graphics.FromImage(image))
                {
                    PaintBackground(g);
                    PaintText(g);
                    PaintTextStain(image);
                    PaintBorder(g);
                    //保存图片数据
                    var stream = new MemoryStream();
                    image.Save(stream, ImageFormat.Gif);
                    //输出图片流
                    return stream.ToArray();
                }
            }
        }
        /// <summary> 
        /// 绘画背景颜色 
        /// </summary> 
        /// <param name="g"></param> 
        private void PaintBackground(Graphics g)
        {
            g.Clear(_background);
        }
        /// <summary> 
        /// 绘画边框 
        /// </summary> 
        /// <param name="g"></param> 
        private void PaintBorder(Graphics g)
        {
            g.DrawRectangle(_borderColor, 0, 0, _width - 1, _height - 1);
        }
        /// <summary> 
        /// 绘画文字 
        /// </summary> 
        /// <param name="g"></param> 
        private void PaintText(Graphics g)
        {
            g.DrawString(Code, _font, GetBrush(), 3, 1);
        }
        /// <summary> 
        /// 绘画文字噪音点和干扰线
        /// </summary> 
        /// <param name="b"></param> 
        private void PaintTextStain(Bitmap b)
        {
            for (int n = 0; n < 50; n++)
            {
                int x = _random.Next(_width);
                int y = _random.Next(_height);
                b.SetPixel(x, y, Color.FromName(BrushName[_brushNameIndex]));
            }
        }
        #endregion
    }

    /// <summary>  
    /// 完美随机验证码  0.10  
    /// Verion:0.10  
    /// Description:随机生成设定验证码，并随机旋转一定角度，字体颜色不同  
    /// </summary>  
    public class Captcha
    {
        /// <summary>  
        /// 生成随机码  
        /// </summary>  
        /// <param  name="length">随机码个数</param>  
        /// <returns></returns>  
        public static string CreateRandomCode(int length)
        {
            var sbCode = new StringBuilder(length);
            //生成一定长度的验证码  
            var random = new Random();
            for (var i = 0; i < length; i++)
            {
                var rand = random.Next();
                char code;
                if (rand % 3 == 0)
                    code = (char)('A' + (char)(rand % 26));
                else
                    code = (char)('0' + (char)(rand % 10));
                sbCode.Append(code);
            }
            return sbCode.ToString();
        }

        /// <summary>  
        /// 创建随机码图片  
        /// </summary>  
        /// <param  name="vcode">验证码</param>
        /// <param name="fontSize">字体大小</param>
        /// <param name="background">背景颜色</param>
        /// <param name="border">边框颜色</param>
        /// <returns>Gif图片二进制流</returns>
        public static byte[] DrawImage(string vcode, float fontSize = 14, Color background = default(Color), Color border = default(Color))
        {
            //随机转动角度 
            const int randAngle = 45;
            //var height = (int) (fontSize + 4);
            var width = vcode.Length * (int)fontSize;
            //创建图片背景 
            using (var map = new Bitmap(width + 3, (int)fontSize + 10))
            {
                using (var graphics = Graphics.FromImage(map))
                {
                    graphics.Clear(background);//清除画面，填充背景  
                    graphics.DrawRectangle(new Pen(border, 0), 0, 0, map.Width - 1, map.Height - 1);//画一个边框  
                    //graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;//模式 
                    var random = new Random();
                    //背景噪点生成
                    var blackPen = new Pen(Color.DarkGray, 0);
                    for (var i = 0; i < 50; i++)
                    {
                        int x = random.Next(0, map.Width);
                        int y = random.Next(0, map.Height);
                        graphics.DrawRectangle(blackPen, x, y, 1, 1);
                    }
                    //验证码旋转，防止机器识别    
                    var chars = vcode.ToCharArray();//拆散字符串成单字符数组  
                    //文字距中  
                    var format = new StringFormat(StringFormatFlags.NoClip)
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center
                    };
                    //定义颜色  
                    Color[] colors = { Color.Black, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple, Color.DarkGoldenrod };

                    FontStyle[] styles = { FontStyle.Bold, FontStyle.Italic, FontStyle.Regular, /*FontStyle.Strikeout,*/ FontStyle.Underline };

                    //定义字体  
                    string[] fonts = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" };
                    foreach (char item in chars)
                    {
                        int cindex = random.Next(8);
                        int findex = random.Next(5);
                        int sindex = random.Next(4);
                        var font = new Font(fonts[findex], fontSize, styles[sindex]);//字体样式(参数2为字体大小)  
                        Brush b = new SolidBrush(colors[cindex]);
                        var dot = new Point(16, 16);
                        //graph.DrawString(dot.X.ToString(),fontstyle,new SolidBrush(Color.Black),10,150);//测试X坐标显示间距的  
                        float angle = random.Next(-randAngle, randAngle);//转动的度数  
                        graphics.TranslateTransform(dot.X, dot.Y);//移动光标到指定位置  
                        graphics.RotateTransform(angle);
                        graphics.DrawString(item.ToString(), font, b, 1, 1, format);
                        //graph.DrawString(chars.ToString(),fontstyle,new SolidBrush(Color.Blue),1,1,format);  
                        graphics.RotateTransform(-angle);//转回去  
                        graphics.TranslateTransform(2, -dot.Y);//移动光标到指定位置  
                    }
                }
                //graph.DrawString(randomcode,fontstyle,new SolidBrush(Color.Blue),2,2); //标准随机码  
                //生成图片  
                var stream = new MemoryStream();
                map.Save(stream, ImageFormat.Gif);
                //输出图片流
                return stream.ToArray();
            }

        }
    }
}